
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <time.h>
#include <stdio.h>

#pragma region DeviceOperations
__global__ void phrases(long * d_inArray, int * d_out_first, int * d_out_last, int * d_out_repeats, int textLength){
    
	int idx = threadIdx.x + blockIdx.x * blockDim.x; // okreťlenie po│o┐enia w╣tku w tablicy wynikˇw
	int repeatCount = 0;
	int phraseSize = blockIdx.x + 2;
	//przepisanie wartosci do shared memory
	__shared__ long s_inArray[2000];
	for(int i = 0; i < textLength; i++) {
		s_inArray[i] = d_inArray[i];
		__syncthreads();
	}
	
	// przygotowanie zwi╣zku frazeologicznego
	long phraseme[8];
		
	for(int i = 0; i < phraseSize; i++)
	{
		phraseme[i] = s_inArray[threadIdx.x+i];
	} 
	
	// przeczesanie tekstu
	for(int i = 0; i <= textLength - phraseSize; i++) // przeczesanie od pierwszego wyrazu po zf do ostatniego wyrazu w tekťcie
	{
		int repeated = 0;
		for(int j = 0 ; j < phraseSize; j++) // sprawdzenie wszystkich
		{
			if(phraseme[j] != s_inArray[i+j]) {
				repeated = 0;
				break;
			}
			repeated = 1;
		}
		repeatCount += repeated;
	}
	
	// przypisanie wartoťci wynikowych
	d_out_first[idx] = threadIdx.x;
	d_out_last[idx] = threadIdx.x + phraseSize - 1;
	d_out_repeats[idx] = repeatCount;
	
}

#pragma endregion

int main(int argc, char ** argv) {
#pragma region Declarations

	long * h_inArray;
	long * d_inArray;
	
	int * h_out_first;
	int * h_out_last;
	int * h_out_repeats;

	int * d_out_first;
	int * d_out_last;
	int * d_out_repeats;

	long tmp[1000];
	int inArrayLength = 0;

#pragma endregion	
#pragma region InputLoad
	FILE* f = fopen("input.file", "r");
	long number = 0;
	int counter = 0;
	
	if (f == NULL) {
		printf("Error during opening input file.\n");
		return -1;
	}
  
    while( fscanf(f, "%ld;", &number) > 0) // parse %ld followed by ';'
    {		
    	tmp[counter] = number;
		counter++;
    }

	h_inArray = (long*) malloc(counter * sizeof(long));
	for(int i = 0; i < counter; i++) {
		h_inArray[i] = tmp[i];
	}
	inArrayLength = counter;

    fclose(f);
#pragma endregion	
#pragma region KernelLaunch
	int totalValues = 7000;

	h_out_first = (int*)malloc(totalValues * sizeof(int));
	h_out_last = (int*)malloc(totalValues * sizeof(int));
	h_out_repeats = (int*)malloc(totalValues * sizeof(int));
	for(int i = 0; i < totalValues; i++)
	{
		h_out_first[i] = 0;
		h_out_last[i] = 0;
		h_out_repeats[i] = 0;
	}

	cudaMalloc((void**) &d_inArray, sizeof(long) * counter);
	cudaMalloc((void**) &d_out_first, totalValues * sizeof(int));
	cudaMalloc((void**) &d_out_last, totalValues * sizeof(int));
	cudaMalloc((void**) &d_out_repeats, totalValues * sizeof(int));

	cudaMemcpy(d_inArray, h_inArray, sizeof(long) * counter, cudaMemcpyHostToDevice);
	clock_t time1 = clock();
	for(int i = 0; i < 10000; i++) {
		phrases<<<7, 128>>>(d_inArray, d_out_first, d_out_last, d_out_repeats, inArrayLength);
	}
	clock_t time2 = clock();
	double interval = (double) (time2 - time1);
	printf("%f\n", interval);
	cudaMemcpy(h_out_first, d_out_first, totalValues * sizeof(int), cudaMemcpyDeviceToHost);
	cudaMemcpy(h_out_last, d_out_last, totalValues * sizeof(int), cudaMemcpyDeviceToHost);
	cudaMemcpy(h_out_repeats, d_out_repeats, totalValues * sizeof(int), cudaMemcpyDeviceToHost);

#pragma endregion
#pragma region PrintResults
	/*for(int i = 0; i < totalValues; i++)
	{
		if(h_out_repeats[i] > 0) {
		
			int first = h_out_first[i];
			int last = h_out_last[i];
			if(first >= 0 && last < inArrayLength) {
				printf("Phrase from thread no. %d ( ", i);
			
			
				for(int j = first; j <= last; j++)
				{
					printf("%ld ", h_inArray[j]);
				}
			
			
				printf(") was repeated %d times.\n", h_out_repeats[i]);
			}
		
		}
	}*/
#pragma endregion
#pragma region OutputResults
	FILE *file; 
	file = fopen("result.file","w+");
	if(file != NULL)
	{
		for(int i = 0; i < totalValues; i++)
		{
		
		
			if(h_out_repeats[i] > 0) {
		
				int first = h_out_first[i];
				int last = h_out_last[i];
				if(first >= 0 && last < inArrayLength) {
			
					for(int j = first; j <= last; j++)
					{
						fprintf(file, "%ld", h_inArray[j]);
						if(j != last)fprintf(file,",");
					}
			
			
					fprintf(file,";%d\n", h_out_repeats[i]);
				}
		
			}

			
		}
	} 
	else 
	{
		printf("Error during writing result file.\n");
		return -2;
	}
	fclose(file);
#pragma endregion
#pragma region Exiting
	free(h_out_first);
	free(h_out_last);
	free(h_out_repeats);
	free(h_inArray);

	
	printf("Success.\n");
	return 0;
#pragma endregion
}

